/*
Copyright (c) [2019年5月1日] [吴超]
[MBT_studio] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/
#include "stdafx.h"
#include "相交.h"


bool f_intersect_线段相交(vec2 a1, vec2 a2, vec2 b1, vec2 b2) {
    const float eps = 1e-8;

    // 计算四个叉积
    float32 d1 = cross(b1 - a1, a2 - a1);
    float32 d2 = cross(b2 - a1, a2 - a1);
    float32 d3 = cross(a1 - b1, b2 - b1);
    float32 d4 = cross(a2 - b1, b2 - b1);

    // 标准相交情况
    if (((d1 > eps && d2 < -eps) || (d1 < -eps && d2 > eps)) &&
        ((d3 > eps && d4 < -eps) || (d3 < -eps && d4 > eps))) {
        return true;
    }

    // 检查端点是否在另一条线段上
    auto point_on_segment = [&](vec2 p, vec2 a, vec2 b) {
        vec2 edge = (b - a);
        vec2 to_p = (p - a);
        float32 crs = cross(edge, to_p);
        float32 edge_len_sq = dot(edge, edge);

        if (abs(crs) > eps * edge_len_sq) return false;

        float32 t = dot(to_p, edge) / edge_len_sq;
        return (t >= -eps && t <= 1.0 + eps);
    };

    if (point_on_segment(b1, a1, a2)) return true;
    if (point_on_segment(b2, a1, a2)) return true;
    if (point_on_segment(a1, b1, b2)) return true;
    if (point_on_segment(a2, b1, b2)) return true;

    return false;
}


bool f_intersect_RayAndAABB(float32 rayOrigin[3], float32 rayDirection[3], float32 boxMin[3], float32 boxMax[3]) {
    float32 tMin = 0.0;
    float32 tMax = 1e20; // 近似无穷大

    for (int32 axis = 0; axis < 3; axis++) {
        // 处理射线方向与坐标轴平行的情况
        if (abs(rayDirection[axis]) < 1e-8) {
            //if (rayOrigin[axis] > boxMax[axis] || rayOrigin[axis] < boxMin[axis]) {
            //    return false;
            //}
            continue;
        }

        // 计算射线与当前轴对应的两个平面的交点参数
        float32 invD = 1.0 / rayDirection[axis];
        float32 tNear = invD * (boxMin[axis] - rayOrigin[axis]);
        float32 tFar = invD * (boxMax[axis] - rayOrigin[axis]);

        // 确保tNear是较小值，tFar是较大值
        if (tNear > tFar) {
            float temp = tNear;
            tNear = tFar;
            tFar = temp;
        }

        // 更新全局的tMin和tMax
        if (tNear > tMin) {
            tMin = tNear;
        }
        if (tFar < tMax) {
            tMax = tFar;
        }

        // 如果区间为空，说明不相交
        if (tMin > tMax) {
            return false;
        }
    }

    return true;
}


int32 f_intersect_射线三角形(const vec3& v1, const vec3& v2, const vec3& v3, const vec3& S, const vec3& dir, vec3* uvt) {
	int32 相交情况 = 0;

	vec3 边A = v2 - v1;
	vec3 边B = v3 - v1;

	//叉积计算
	vec3 pvec = vec_cross(dir, 边B);

	float32 det = vec_dot(边A, pvec);
	vec3 tvec;
	//判断是否正面穿过
	if (det >= 0) {
		//-------------------不要归一化--------------------
		tvec = vec_sub(S, v1);
		相交情况 = 1;
	}
	else {
		//-------------------不要归一化--------------------
		tvec = vec_sub(v1, S);
		det = -det;
		相交情况 = 2;
	}
	if (det < 0.00000001f)    return 0;

	//vec_normalize(&tvec);
	//u
	uvt->x = vec_dot(tvec, pvec);
	if (uvt->x < 0.0f || uvt->x > det) return 0;

	vec3 qvec = vec_cross(tvec, 边A);

	//v
	uvt->y = vec_dot(dir, qvec);
	if (uvt->y  < 0.0f || uvt->x + uvt->y  > det) {
		return 0;
	}
	//t
	uvt->z = vec_dot(边B, qvec);
	float32 inv_det = 1.0f / det;

	//uvt->z *= inv_det; 
	if (uvt->z * inv_det < 1e-6) {
		return 0;
	}



	vec_mul(uvt, inv_det);
	*uvt = dir * uvt->z + S;

	return 相交情况;
}

bool f_intersect_射线三角形(const vec3& v1, const vec3& v2, const vec3& v3, const vec3& S, const vec3& dir) {
	int32 相交情况 = 0;

	vec3 边A = v2 - v1;
	vec3 边B = v3 - v1;

	//叉积计算
	vec3 pvec = vec_cross(dir, 边B);

	float32 det = vec_dot(边A, pvec);
	vec3 tvec;
	//判断是否正面穿过
	if (det > 0) {
		//-------------------不要归一化--------------------
		tvec = vec_sub(S, v1);
		相交情况 = 1;
	}
	else {
		//-------------------不要归一化--------------------
		tvec = vec_sub(v1, S);
		det = -det;
		相交情况 = 2;
	}
	if (det < 0.00000001f) return 0;

	
	//u
	float32 u = vec_dot(tvec, pvec);
	if (u< 0.0f || u > det) return 0;

	vec3 qvec = vec_cross(tvec, 边A);

	//v
	float32 v = vec_dot(dir, qvec);
	if (v  < 0.0f || u + v  > det) {
		return 0;
	}


	float32 t = vec_dot(边B, qvec);  // t的分子部分
	float32 inv_det = 1.0f / det;
	t *= inv_det;  // 归一化得到实际t值

	if (t < 1e-6) {
		return 0;  // 交点在起点后方，无效
	}

	return 相交情况;
}

bool f_intersect_点在多边形内(vec2 point, const vec2* polygon, uint32 num) {
	if (num < 3) return false;

	bool inside = false;
	for (int32 i = 0, j = num - 1; i < num; j = i++) {
		vec2 xyi = polygon[i];
		vec2 xyj = polygon[j];

		// 检查点是否在边的范围内
		bool yInRange = (xyi.y > point.y) != (xyj.y > point.y);
		if (!yInRange) continue;

		// 计算射线与边的交点x坐标
		float32 xIntersect = ( (point.y - xyi.y) * (xyj.x - xyi.x) ) / (xyj.y - xyi.y) + xyi.x;
		if (point.x < xIntersect) inside = !inside;
	}
	return inside;
}



